package cn.explink.distributor.framework;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import org.apache.log4j.Logger;

import cn.explink.distributor.framework.enums.ConditionTypeEnum;
import cn.explink.distributor.framework.exception.NoneTargetFoundException;
import cn.explink.dop.entity.vo.OrderVO;

public abstract class AbstractDistributor implements Distributor {

	@SuppressWarnings("unused")
	private static final Logger LOGGER = Logger.getLogger(AbstractDistributor.class);

	/**
	 * 分单目标对象
	 */
	private List<Target> targetList;

	public AbstractDistributor(List<Target> targetList) {
		this.targetList = targetList;
	}
	
	public void initTargetList(){
		for(Target temp: targetList){
			temp.setKnockOutFalse();
		}
	}
	@Override
	public List<Target> distribute(Order order, boolean getBestFitTarget) {
		// 1、组装分单条件(按照优先级排序)
		// List<Condition> distributeConditionList = this.assembleCondition();

		// 2、判断是否符合要求并淘汰掉不符合要求的
		this.judgeAndKnockOut(order);

		// 3、筛选出最终的分单对象
		List<Target> leftTargetList = this.getLeftTargetList(); 
		if (leftTargetList.size() == 0) {
			String msg = "没有找到合适的分单对象";
			throw new NoneTargetFoundException(msg);
		}
		Collections.sort(leftTargetList);
		if (getBestFitTarget) {
			return this.filterAndGetTarget(order, leftTargetList);
		} else {
			return leftTargetList;
		}
	}

	private List<Target> filterAndGetTarget(Order order, List<Target> leftTargetList) {
		List<Target> resultTargetList = new ArrayList<Target>();
		Target maxScoreTarget = leftTargetList.get(0);
		if (this.getLeftTargetCount() != 1) {
			Target secondMaxScoreTarget = leftTargetList.get(1);
			// 取分数最大的分单对象
			if (maxScoreTarget.getScore() != secondMaxScoreTarget.getScore()) {
				resultTargetList.add(maxScoreTarget);
			} else {
				// 分数相等，则获取所有分数最大且相等的分单对象，随机取一个
				List<Target> scoreEqualsTargetList = this.getScoreEqualsTargetList(leftTargetList, maxScoreTarget, secondMaxScoreTarget);
				Random random = new Random();
				resultTargetList.add(scoreEqualsTargetList.get(random.nextInt(scoreEqualsTargetList.size())));
			}
		} else {
			resultTargetList.add(maxScoreTarget);
		}
		return resultTargetList;
	}

	private void judgeAndKnockOut(Order order) {
		// 循环所有订单的分单条件和分单对象具有的分单能力
		// for (Condition condition : distributeConditionList) {
		List<CommonCondition> orderConditionList=new ArrayList<CommonCondition>();
		if(order instanceof OrderCluster){
			OrderCluster ordercluster = (OrderCluster)order;
			for (Order orderInCluster : ordercluster.getOrderList()) {
				orderConditionList.addAll(orderInCluster.getConditionList());
			}
		}else if(order instanceof Order){
			orderConditionList.addAll(order.getConditionList());
		}else{
			orderConditionList=order.getConditionList();
		}
		for (Condition orderCondition : orderConditionList) {
			for (Target target : this.targetList) {
				// 如果分单对象已经被淘汰，则跳过
				if (target.isKnockOut()) {
					continue;
				}
				List<CommonCondition> distributeAbilityList = target.getDistributeAbilityList();
				for (Condition distributeAbility : distributeAbilityList) {
					if (orderCondition.getClass().equals(distributeAbility.getClass())) {
						// 获取条件类型（Matchable(1, "可匹配的"), Comparable(2,
						// "可比较的");）
						int type = distributeAbility.getType();
						if (type == ConditionTypeEnum.Matchable.getValue()) {
							// 硬性条件，不匹配则被淘汰
							if (!distributeAbility.isMatched(orderCondition)) {
								target.setKnockOut();
							}
						} else if (type == ConditionTypeEnum.Comparable.getValue()) {
							if (!distributeAbility.isComparableMatched(orderCondition, this.targetList)) {
								target.decreaseScore(orderCondition.getWeight());
							}
						}
					}
				}
				// 得分为负的被淘汰
				if (target.getScore() < 0) {
					target.setKnockOut();
				}
			}
		}		
	}

	@SuppressWarnings("unused")
	private List<Condition> assembleCondition() {
		Set<Condition> conditionSet = new HashSet<Condition>();
		for (Target target : this.targetList) {
			conditionSet.addAll(target.getDistributeAbilityList());
		}
		List<Condition> distributeConditionList = new ArrayList<Condition>(conditionSet);
		Collections.sort(distributeConditionList);
		return distributeConditionList;
	}

	private List<Target> getScoreEqualsTargetList(List<Target> leftTargetList, Target maxScoreTarget, Target secondMaxScoreTarget) {
		List<Target> scoreEqualsTargetList = new ArrayList<Target>();
		scoreEqualsTargetList.add(maxScoreTarget);
		scoreEqualsTargetList.add(secondMaxScoreTarget);
		for (int i = 2; i < leftTargetList.size(); i++) {
			Target target = leftTargetList.get(i);
			if (maxScoreTarget.getScore() == target.getScore()) {
				scoreEqualsTargetList.add(target);
			} else {
				break;
			}
		}
		return scoreEqualsTargetList;
	}

	private int getLeftTargetCount() {
		int count = this.targetList.size();
		for (Target target : this.targetList) {
			if (target.isKnockOut()) {
				count--;
			}
		}
		return count;
	}

	private List<Target> getLeftTargetList() {
		List<Target> leftTargetList = new ArrayList<Target>();
		for (Target target : this.targetList) {
			if (!target.isKnockOut()) {
				leftTargetList.add(target);
			}
		}
		return leftTargetList;
	}
}
